/*
 * Copyright (c) 2009-2013 EvTech Project
 * All rights reserved.
 * 
 * This file is part of LModeller.
 *
 * LModeller is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 *
 * LModeller is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LModeller.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package fi.honkalampisaatio.lmodeller.ui;

import java.awt.Font;

import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Rectangle;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;

import fi.honkalampisaatio.lmodeller.LModeller;
import fi.honkalampisaatio.lmodeller.blocks.Block;
import fi.honkalampisaatio.lmodeller.blocks.BlockModel;
import fi.honkalampisaatio.lwjgl.TrueTypeFont;
import glapp.GLApp;
import glmodel.GLModel;


public class Model3DView extends UIElement {
	public enum VIEWMODES {AUTO, MANUAL, FRONT};
	private VIEWMODES viewMode = VIEWMODES.FRONT;
	
	BlockModel model;
    GLModel block_4x2;
    GLModel block_2x2;
    GLModel plate_4x2;
    Vector3f rotation = new Vector3f();
    Vector3f rotationSpeed = new Vector3f(0,30,0);
    float scale = 0.01f;
    float cameraZ, zoom;
    boolean isDebugMode = false;
    boolean bShowCount = false;
    TrueTypeFont ttFont;
	int fontHeight;
	float[] textColor;
	
	public Model3DView(Rectangle rectangle) {
		super(rectangle);
	}

	public BlockModel getModel() {
		return model;
	}

	public void setModel(BlockModel model, boolean resetCamera) {
		this.model = model;
    	this.cameraZ = 0;
    	this.zoom = 1;
    	if(model!=null)
		{
            this.cameraZ = model.getSize().length()*scale+
            	(float)Math.sqrt(model.getSize().length()*scale*3f);
		}
    	this.cameraZ = (this.cameraZ<3f?3f:this.cameraZ)/1.2f;
    	if(resetCamera)
    	{
    		this.rotation.set(20, 20, 0); 
    		refreshViewMode();
    	}
	}

	public void paint() {
		if(model==null)
		{
			return;
		}
    	// use the frames per second to animate
		GL11.glPushMatrix();
    	GLApp.setColor(0.1f,0.1f,0.15f, .8f);
    	GL11.glEnable(GL11.GL_TEXTURE_2D);
		fillRect(this.getBounds().getX(), 
				this.getBounds().getY(), this.getBounds().getWidth(), this.getBounds().getHeight());
        GLApp.setColor(GLApp.colorWhite);
        GL11.glEnable(GL11.GL_LIGHTING);
		GL11.glViewport(getBounds().getX(), getBounds().getY(), 
				getBounds().getWidth(), getBounds().getHeight());
		if(viewMode==VIEWMODES.AUTO)
		{
	    	rotation.x += rotationSpeed.x * GLApp.getSecondsPerFrame();
	    	rotation.y += rotationSpeed.y * GLApp.getSecondsPerFrame();
	    	rotation.z += rotationSpeed.z * GLApp.getSecondsPerFrame();
		}
		if(zoom<=0) zoom = 1;
        GLU.gluLookAt(0, 0, cameraZ/zoom, // where is the eye
					// look at a center
					0, 0, 0,//LModelling.cameraPos.z,
        			0f, 1f, 0f);   // which way is up
        
        
        GL11.glRotatef(rotation.x, 1, 0, 0);  // turn it
        GL11.glRotatef(rotation.y, 0, 1, 0);  // turn it
        GL11.glRotatef(rotation.z, 0, 0, 1);  // turn it
        
        if(model.getSize().x<model.getSize().z)
        	GL11.glRotatef(90, 0, 1, 0);
        	
		Vector3f translateVector = new Vector3f();
		translateVector.set((model.getSize().x/2 + model.getLocation().x)*scale,
				(model.getSize().y/2 + model.getLocation().y)*scale,
				(model.getSize().z/2 + model.getLocation().z)*scale);
		
		GL11.glTranslatef(translateVector.x, translateVector.y, translateVector.z);
		
		for(int i=0; i<model.getBlocks().size();i++)
		{
			Block block = model.getBlocks().get(i);
			GL11.glPushMatrix();

	        GL11.glTranslatef(-block.getX()*scale, 
	        		(-block.getY()+(block.getHeight()/2))*scale, 
	        		-block.getZ()*scale);
	        GL11.glRotatef(block.getRotate(), 0, 1, 0);
	        GL11.glScalef(0.99f, 0.99f, 0.99f);
	        
	        switch(block.getColor())
	        {
	        case BLACK:
	        	GLApp.setColor(0.05f, 0.05f, 0.05f, 1f);
	        	break;
	        case BLUE:
	        	GLApp.setColor(0.1f, 0.0f, 0.7f, 1f);
	        	break;
	        case GREEN:
	        	GLApp.setColor(0.0f, 0.3f, 0.0f, 1f);
	        	break;
	        case RED:
	        	GLApp.setColor(0.7f, 0.0f, 0.0f, 1f);
	        	break;
	        case LIGHTGREEN:
	        	GLApp.setColor(0.4f, 0.4f, 0.0f, 1f);
	        	break;
	        case YELLOW:
	        	GLApp.setColor(0.8f, 0.65f, 0.0f, 1f);
	        	break;
	        case WHITE:
	        	GLApp.setColor(0.9f, 0.9f, 0.9f, 1f);
	        	break;
	        case ORANGE:
	        	GLApp.setColor(1.0f, 0.3f, 0.0f, 1f);
	        	break;
	        case TRANSBLUE:
	        	GLApp.setColor(0.1f, 0.1f, 0.8f, 0.6f);
	        	break;
	        default:
	        	GLApp.setColor(0.3f, 0.3f, 0.3f, .5f);
	        	break;
	        }
	        
	        switch(block.getType())
	        {
	        case BASIC2x2:
	        	block_2x2.render();
	        	break;
	        case BASIC4x2:
	        	block_4x2.render();
	        	break;
	        case PLATE4x2:
	        	plate_4x2.render();
	        	break;
	        }
	        GLApp.setColor(GLApp.colorWhite);
	        GL11.glPopMatrix();
		}
        GL11.glDisable(GL11.GL_LIGHTING);
        if(bShowCount && model!=null && model.getBlocks()!=null)
        {
            GLApp.setColor(textColor);
        	GL11.glEnable(GL11.GL_TEXTURE_2D);
			TrueTypeFont.set2DMode(0, GLApp.getWidth(), 0, GLApp.getHeight());

			ttFont.drawString(0, 0, Integer.toString(model.getBlocks().size()), 
					10.0f, 10.0f, TrueTypeFont.ALIGN_LEFT);
			
			TrueTypeFont.set3DMode();
        }
        if(isDebugMode)
        {
            GLApp.setColor(textColor);
        	GL11.glEnable(GL11.GL_TEXTURE_2D);
			TrueTypeFont.set2DMode(0, GLApp.getWidth(), 0, GLApp.getHeight());
			ttFont.drawString(0, GLApp.getHeight() - 1 * fontHeight, "Debug window", 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 2 * fontHeight, "modelSize " + 
					model.getSize().toString(), 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 3 * fontHeight, "rotation " + 
					rotation.toString(), 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 4 * fontHeight, "rotationSpeed " + 
					rotationSpeed.toString(), 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 5 * fontHeight, "translateVector " + 
					translateVector.toString(), 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 6 * fontHeight, "cameraZ " + 
					cameraZ/zoom,1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 7 * fontHeight, "FPS " + 
					(int)GLApp.getFramesPerSecond(), 1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
			ttFont.drawString(0, GLApp.getHeight() - 8 * fontHeight, "LightGreen (Red:" + LModeller.testColor[0] + 
					", green:"+LModeller.testColor[1]+", blue:" + LModeller.testColor[2]+ ")", 
					1.0f, 1.0f, TrueTypeFont.ALIGN_LEFT);
					
			TrueTypeFont.set3DMode();
			
        }
		GL11.glViewport(0, 0, GLApp.getWidth(), GLApp.getHeight());
        GLApp.setColor(GLApp.colorWhite);
        GL11.glPopMatrix();
		
	}

	public void setup() {
		textColor = GLApp.colorWhite;
        block_4x2 = new GLModel("data/block_4x2.obj");
        block_4x2.regenerateNormals();
        block_2x2 = new GLModel("data/block_2x2.obj");
        block_2x2.regenerateNormals();
        plate_4x2 = new GLModel("data/plate_4x2.obj");
        plate_4x2.regenerateNormals();

        fontHeight = GLApp.getHeight()/30;
        Font font;
		if(TrueTypeFont.isSupported(LModeller.getGameSetting().getFontName()))
		{
			font = new Font(LModeller.getGameSetting().getFontName(), Font.BOLD, fontHeight);
		}
		else
		{
			font = new Font("Arial", Font.BOLD, fontHeight);
			System.out.println("Font "+LModeller.getGameSetting().getFontName()+" not supported, using Arial");
		}
		ttFont = new TrueTypeFont(font, true);
    	zoom = 1;
	}

	protected void refreshViewMode()
	{
		switch(viewMode)
		{
			case AUTO:
		    	rotation.x = 30;
		    	rotation.z = 0;
				break;
			case MANUAL:
				break;
			default: // FRONT
		    	rotation.set(0, 0, 0);
		        break;
		}
	}
	
	public void setViewMode(VIEWMODES viewMode) {
		this.viewMode = viewMode;
		refreshViewMode();
	}

	public VIEWMODES getViewMode() {
		return viewMode;
		
	}
	
	public void addRotate(float x, float y, float z)
	{
		this.rotation.x += x;
		this.rotation.y += y;
		this.rotation.z += z;
	}

	public void toggleDebugMode() {
		isDebugMode = (isDebugMode)?false:true;
	}

	public void setZoom(float zoom) {
		this.zoom = zoom;
	}

	public void setShowBlockCount(boolean showCount, float[] textColor) {
		this.bShowCount = showCount;
		this.textColor = textColor;
	}
}
